package com.sonix.oidbluetooth.service;

import android.Manifest;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;

import com.sonix.app.Api;
import com.sonix.app.App;
import com.sonix.base.BeiDot;
import com.sonix.oidbluetooth.ElementActivity;
import com.sonix.oidbluetooth.MainActivity;
import com.sonix.oidbluetooth.R;
import com.sonix.util.Events;
import com.tqltech.tqlpencomm.BLEException;
import com.tqltech.tqlpencomm.BLEScanner;
import com.tqltech.tqlpencomm.PenCommAgent;
import com.tqltech.tqlpencomm.bean.Dot;
import com.tqltech.tqlpencomm.bean.ElementCode;
import com.tqltech.tqlpencomm.bean.PenStatus;
import com.tqltech.tqlpencomm.listener.TQLPenSignal;
import com.tqltech.tqlpencomm.util.BLELogUtil;

import org.greenrobot.eventbus.EventBus;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

/**
 * 服务接收数据
 */
public class BeibiService extends Service {
    private final static String TAG = "BeibiService";
    private String mBluetoothDeviceAddress;
    private Handler handlerThree = new Handler(Looper.getMainLooper());

    public final static String ACTION_GATT_CONNECTED = "ACTION_GATT_CONNECTED";
    public final static String ACTION_GATT_DISCONNECTED = "ACTION_GATT_DISCONNECTED";
    public final static String ACTION_GATT_CONNECT = "ACTION_GATT_CONNECT";
    public final static String ACTION_DATA_AVAILABLE = "ACTION_DATA_AVAILABLE";
    public final static String ACTION_PEN_STATUS_CHANGE = "ACTION_PEN_STATUS_CHANGE";
    public final static String RECEVICE_DOT = "RECEVICE_DOT";
    public final static String RECEVICE_USB_STATUS = "RECEVICE_USB_STATUS";

    private Intent intent = new Intent(RECEVICE_DOT);
    public final static String DEVICE_DOES_NOT_SUPPORT_UART = "DEVICE_DOES_NOT_SUPPORT_UART";
    private PenCommAgent bleManager;
    private boolean isRequesting;
    private boolean isPenConnected = false;
    private String deviceMac;
    private boolean isScanning;
    private int connInterId;
    private volatile int syncInterId;
    private long syncTime;
    private boolean offlineProcess = false;
    private int offlineDealNum = 0;
    private int offlineDataNum = 0;
    private long time;

    private List<BeiDot> tmpDots = Collections.synchronizedList(new ArrayList<BeiDot>());        //待上传缓存数据
    private List<BeiDot> lewerDots = Collections.synchronizedList(new ArrayList<BeiDot>());        //最新部分缓存数据

    private MsgReceiver msgReceiver;

    Timer timer = new Timer();
    TimerTask tt ;
    public TimerTask  getRbTask() {
        return new TimerTask() {
            @Override
            public void run() {
                requestBluetooth();
            }
        };
    }

    public TimerTask  getDotTask() {
        return new TimerTask() {
            @Override
            public void run() {
                Api.uploadDots(tmpDots);
                tmpDots.clear();
            }
        };
    }

    @Override
    public void onCreate() {
        super.onCreate();
        initialize();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i("Beibi", "onStartCommand - startId = " + startId + ", Thread ID = " + Thread.currentThread().getId());
        if (!bleManager.isConnect()) {
            tt = getRbTask();
            timer.schedule(tt,1000,5000);
        }
        return super.onStartCommand(intent, flags, startId);
    }

    /**
     * 请求蓝牙权限
     */
    private void requestBluetooth() {
        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
        if (adapter == null || !adapter.isEnabled()) {
            if (isRequesting)
                return;
            isRequesting = true;
        } else {
            isRequesting = false;
            //if (isScanning)
            //    return;
            isScanning = true;
            bleManager.FindAllDevices(scanCallback);
        }
    }

    public final void deviceConnect(String name, String address) {
        isPenConnected = false;
        EventBus.getDefault().post(new Events.DeviceConnecting(name, address));
        if (address.equals(deviceMac) && bleManager.isConnect(address)) {
            isPenConnected = true;
            EventBus.getDefault().post(new Events.DeviceConnected());
            return;
        }
        if (bleManager.isConnect(deviceMac))
            bleManager.disconnect(deviceMac);
        App.getInstance().setDeviceName(name);
        App.getInstance().setDeviceAddress(address);
        deviceMac = address;
        bleManager.connect(deviceMac);
    }

    /**
     * 蓝牙扫描回调
     */
    BLEScanner.OnBLEScanListener scanCallback = new BLEScanner.OnBLEScanListener() {

        @Override
        public void onScanResult(final BluetoothDevice device, int rssi, byte[] scanRecord) {
            Log.i(TAG, "onScanResult: " + device.getAddress());
            if (!isToneSmartPen(scanRecord))
                return;
            deviceConnect(device.getName(), device.getAddress());
        }

        /**
         * SmartPen过滤
         *
         * @param scanRecord 蓝牙返回字节数组
         * @return 是否为SmartPen
         */
        private boolean isToneSmartPen(byte[] scanRecord) {
            String ret = bytesToHexString(scanRecord);
            return ret.contains("FF31323334");
        }

        @Override
        public void onScanFailed(BLEException bleException) {
            Log.e(TAG, bleException.getMessage());
            isScanning = false;
        }
    };
    /**
     * Byte数组转String
     *
     * @param bytes 字节数组
     * @return 16进制字符串
     */
    private String bytesToHexString(byte[] bytes) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : bytes) {
            String plainText = Integer.toHexString(0xFF & b);
            if (plainText.length() < 2)
                plainText = "0" + plainText;
            hexString.append(plainText);
        }
        return hexString.toString().toUpperCase();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    /**
     * Initializes a reference to the local Bluetooth adapter.
     *
     * @return Return true if the initialization is successful.
     */
    public boolean initialize() {
        bleManager = PenCommAgent.GetInstance(getApplication());
        bleManager.setTQLPenSignalListener(mPenSignalCallback);
        if (!bleManager.isSupportBluetooth()) {
            Log.e(TAG, "Unable to Support Bluetooth");
            return false;
        }

        if (!bleManager.isSupportBLE()) {
            Log.e(TAG, "Unable to Support BLE.");
            return false;
        }
        //动态注册广播接收器
        msgReceiver = new MsgReceiver();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(BeibiService.ACTION_GATT_CONNECT);
        registerReceiver(msgReceiver, intentFilter);
        return true;
    }

    public boolean getPenStatus() {
        return isPenConnected;
    }

    private void broadcastUpdate(final String action) {
        final Intent intent = new Intent(action);
        sendBroadcast(intent);
    }

    public class LocalBinder extends Binder {
        public BeibiService getService() {
            return BeibiService.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        // After using a given device, you should make sure that BluetoothGatt.close() is called
        // such that resources are cleaned up properly.  In this particular example, close() is
        // invoked when the UI is disconnected from the Service.

        BLELogUtil.i(TAG, "BluetoothLEService onUnbind");
        close();
        return super.onUnbind(intent);
    }

    public void close() {
        if (bleManager == null) {
            return;
        }

        Log.w(TAG, "mBluetoothGatt closed");
        BLELogUtil.i(TAG, "BluetoothLEService close");
        bleManager.disconnect(mBluetoothDeviceAddress);
        mBluetoothDeviceAddress = null;
        bleManager = null;
    }

    public class MsgReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action  = intent.getAction();
            if (BeibiService.ACTION_GATT_CONNECT.equals(action)) {
                String devName = intent.getStringExtra("devName");
                String devAddr = intent.getStringExtra("devAddr");
                deviceConnect(devName, devAddr);
            }
        }
    }


    private final IBinder mBinder = new LocalBinder();

    private TQLPenSignal mPenSignalCallback = new TQLPenSignal() {

        /**********************************************************/
        /****************** part1: 蓝牙连接相关 *******************/
        /**********************************************************/
        @Override
        public void onConnected() {
            Log.i(TAG, "TQLPenSignal had onConnected");
            tt.cancel();
            String intentAction;
            intentAction = ACTION_GATT_CONNECTED;
            broadcastUpdate(intentAction);
            bleManager.getPenOfflineDataList();
            bleManager.stopFindAllDevices();;
            App.getInstance().setDeviceConnected(true);
            isPenConnected = true;
        }

        @Override
        public void onDisconnected() {
            tt = getRbTask();
            timer.schedule(tt,1000,10000);
            String intentAction;
            Log.i(TAG, "TQLPenSignal had onDisconnected");
            intentAction = ACTION_GATT_DISCONNECTED;
            broadcastUpdate(intentAction);
            App.getInstance().setDeviceConnected(false);
            deviceMac = "";
            isPenConnected = false;
            bleManager.FindAllDevices(scanCallback);
        }

        @Override
        public void onConnectFailed() {
            deviceMac = "";
            tt = getRbTask();
            timer.schedule(tt,1000,10000);
            String intentAction;
            Log.i(TAG, "TQLPenSignal had onConnectFailed");
            intentAction = ACTION_GATT_DISCONNECTED;
            broadcastUpdate(intentAction);
            App.getInstance().setDeviceConnected(false);
            isPenConnected = false;
            handlerThree.post(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(getApplicationContext(), "连接失败", Toast.LENGTH_SHORT).show();
                }
            });
        }

        /**********************************************************/
        /****************** part2: 在线数据    *******************/
        /**********************************************************/
        @Override
        public void onReceiveDot(Dot dot) {
            Log.d(TAG, "online:" + dot.toString());
            if (dot!=null) {
                BeiDot bd = new BeiDot(dot ,deviceMac);
                lewerDots.add(bd);
                intent.putExtra("dot", dot);
                sendBroadcast(intent);
                if (dot.type == Dot.DotType.PEN_UP) {
                    syncInterId++;
                    tmpDots.addAll(lewerDots);
                    lewerDots.clear();
                }
                if(tt!=null) {
                    tt.cancel();
                }
                if(syncInterId==10) {
                    syncInterId = 0;
                    Api.uploadDots(tmpDots);
                    tmpDots.clear();
                } else {
                    tt = getRbTask();
                    timer.schedule(tt,5000);
                }
            }
        }

        /**********************************************************/
        /****************** part3: 离线数据    *******************/
        /**********************************************************/
        @Override
        public void onReceiveOfflineStrokes(Dot dot) {
            Log.i(TAG, "onOfflineDataReceive");
            if(dot!=null) {
                BeiDot bd = new BeiDot(dot ,deviceMac);
                offlineDealNum++;
                if(offlineDealNum>=offlineDataNum){
                    offlineProcess = false;
                    bleManager.RemoveOfflineData();
                    offlineDataNum = 0;
                }
                synchronized (lewerDots) {
                    synchronized (tmpDots) {
                        lewerDots.add(bd);
                        if (dot.type == Dot.DotType.PEN_UP) {
                            tmpDots.addAll(lewerDots);
                            lewerDots.clear();
                        }
                    }
                }
            }
        }

        @Override
        public void onOfflineDataList(int offlineNotes) {
            Log.i(TAG, "onOfflineDataNum");
            offlineDataNum = offlineNotes;
            if(offlineNotes>0) {
                bleManager.ReqOfflineDataTransfer(true);
            }
        }

        @Override
        public void onStartOfflineDownload(final boolean isSuccess) {
            handlerThree.post(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(getApplicationContext(), "StartOffline-->" + isSuccess, Toast.LENGTH_SHORT).show();
                }
            });
        }

        @Override
        public void onStopOfflineDownload(boolean isSuccess) {

        }

        @Override
        public void onPenPauseOfflineDataTransferResponse(boolean isSuccess) {
            Log.i(TAG, "onPenPauseOfflineDataTransferResponse: " + isSuccess);
        }

        @Override
        public void onPenContinueOfflineDataTransferResponse(final boolean isSuccess) {
            Log.i(TAG, "onPenContinueOfflineDataTransferResponse: " + isSuccess);
            handlerThree.post(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(getApplicationContext(), "ContinueOffline-->" + isSuccess, Toast.LENGTH_SHORT).show();
                }
            });
        }

        @Override
        public void onFinishedOfflineDownload(boolean isSuccess) {
            Log.i(TAG, "-------offline download success-------");
            if(isSuccess) {
                Api.uploadDots(tmpDots);
                bleManager.RemoveOfflineData();
            }
        }

        @Override
        public void onReceiveOfflineProgress(int i) {
            Log.i(TAG, "onReceiveOfflineProgress----" + i);
        }

        @Override
        public void onPenDeleteOfflineDataResponse(boolean isSuccess) {

        }


        /**********************************************************/
        /****************** part4: 请求的回复   *******************/
        /**********************************************************/
        @Override
        public void onReceivePenAllStatus(PenStatus status) {
            App.mBattery = status.mPenBattery;
            App.mUsedMem = status.mPenMemory;
            App.mTimer = status.mPenTime;
            Log.e(TAG, "ApplicationResources.mTimer is " + App.mTimer + ", status is " + status.toString());
            App.mPowerOnMode = status.mPenPowerOnMode;
            App.mPowerOffTime = status.mPenAutoOffTime;
            App.mBeep = status.mPenBeep;
            App.mPenSens = status.mPenSensitivity;
            App.tmp_mEnableLED = status.mPenEnableLed;

            App.mPenName = status.mPenName;
            App.mBTMac = status.mPenMac;
            App.mFirmWare = status.mBtFirmware;
            App.mMCUFirmWare = status.mPenMcuVersion;
            App.mCustomerID = status.mPenCustomer;

            App.mTwentyPressure = status.mPenTwentyPressure;
            App.mThreeHundredPressure = status.mPenThirdPressure;

            String intentAction = ACTION_PEN_STATUS_CHANGE;
            broadcastUpdate(intentAction);
        }

        @Override
        public void onReceivePenMac(String penMac) {
            Log.e(TAG, "receive pen Mac " + penMac);
            mBluetoothDeviceAddress = penMac;
            App.mBTMac = penMac;
        }

        @Override
        public void onReceivePenName(String penName) {

        }

        @Override
        public void onReceivePenBtFirmware(String penBtFirmware) {

        }

        @Override
        public void onReceivePenTime(long penTime) {
            App.mTimer = penTime;
            String intentAction = ACTION_PEN_STATUS_CHANGE;
            broadcastUpdate(intentAction);
        }

        @Override
        public void onReceivePenBattery(int penBattery, boolean bIsCharging) {
            Log.e(TAG, "receive pen battery is " + penBattery);
        }

        @Override
        public void onReceivePenMemory(int penMemory) {

        }

        @Override
        public void onReceivePenAutoPowerOnModel(boolean bIsOn) {

        }

        @Override
        public void onReceivePenBeepModel(boolean bIsOn) {

        }

        @Override
        public void onReceivePenAutoOffTime(int autoOffTime) {

        }

        @Override
        public void onReceivePenMcuVersion(String penMcuVersion) {

        }

        @Override
        public void onReceivePenCustomer(String penCustomerID) {

        }

        @Override
        public void onReceivePenSensitivity(int penSensitivity) {

        }

        @Override
        public void onReceivePenTypeInt(int penType) {
            App.mPenType = penType;

        }

        @Override
        public void onReceivePenType(String penType) {

        }

        @Override
        public void onReceivePenDataType(byte penDataType) {

        }

        @Override
        public void onReceivePenDotType(int penDotType) {

        }

        @Override
        public void onReceivePenLedConfig(int penLedConfig) {
            Log.e(TAG, "receive hand write color is " + penLedConfig);

        }

        @Override
        public void onReceivePenEnableLed(boolean bEnableFlag) {

        }

        @Override
        public void onReceivePresssureValue(int minPressure, int maxPressure) {

        }


        /**********************************************************/
        /****************** part5: 设置的回复   *******************/
        /**********************************************************/
        @Override
        public void onPenNameSetupResponse(boolean bIsSuccess) {
            if (bIsSuccess) {
                App.mPenName = App.tmp_mPenName;
            }
            String intentAction = ACTION_PEN_STATUS_CHANGE;
            Log.i(TAG, "Disconnected from GATT server.");
            broadcastUpdate(intentAction);
            handlerThree.post(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(getApplicationContext(), "设置名字成功", Toast.LENGTH_SHORT).show();
                }
            });
        }

        @Override
        public void onPenTimetickSetupResponse(boolean bIsSuccess) {
            if (bIsSuccess) {
                App.mTimer = App.tmp_mTimer;
            }
            String intentAction = ACTION_PEN_STATUS_CHANGE;
            Log.i(TAG, "Disconnected from GATT server.");
            broadcastUpdate(intentAction);
            handlerThree.post(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(getApplicationContext(), "设置RTC时间成功", Toast.LENGTH_SHORT).show();
                }
            });
        }

        @Override
        public void onPenAutoShutdownSetUpResponse(boolean bIsSuccess) {
            if (bIsSuccess) {
                App.mPowerOffTime = App.tmp_mPowerOffTime;
            }
            String intentAction = ACTION_PEN_STATUS_CHANGE;
            Log.i(TAG, "Disconnected from GATT server.");
            broadcastUpdate(intentAction);
            handlerThree.post(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(getApplicationContext(), "设置自动关机时间成功", Toast.LENGTH_SHORT).show();
                }
            });
        }

        @Override
        public void onPenFactoryResetSetUpResponse(boolean bIsSuccess) {

        }

        @Override
        public void onPenAutoPowerOnSetUpResponse(boolean bIsSuccess) {
            if (bIsSuccess) {
                App.mPowerOnMode = App.tmp_mPowerOnMode;
            }
            String intentAction = ACTION_PEN_STATUS_CHANGE;
            Log.i(TAG, "Disconnected from GATT server.");
            broadcastUpdate(intentAction);
        }

        @Override
        public void onPenBeepSetUpResponse(boolean bIsSuccess) {
            if (bIsSuccess) {
                App.mBeep = App.tmp_mBeep;
            }
            String intentAction = ACTION_PEN_STATUS_CHANGE;
            Log.i(TAG, "Disconnected from GATT server.");
            broadcastUpdate(intentAction);
        }

        @Override
        public void onPenSensitivitySetUpResponse(boolean bIsSuccess) {
            if (bIsSuccess) {
                App.mPenSens = App.tmp_mPenSens;
            }
            String intentAction = ACTION_PEN_STATUS_CHANGE;
            Log.i(TAG, "Disconnected from GATT server.");
            broadcastUpdate(intentAction);
            handlerThree.post(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(getApplicationContext(), "设置灵敏度成功", Toast.LENGTH_SHORT).show();
                }
            });
        }

        @Override
        public void onPenLedConfigResponse(boolean bIsSuccess) {

        }

        @Override
        public void onPenDotTypeResponse(boolean bIsSuccess) {

        }

        @Override
        public void onPenWriteCustomerIDResponse(boolean bIsSuccess) {

        }

        @Override
        public void onPenChangeLedColorResponse(boolean bIsSuccess) {

        }


        /**********************************************************/
        /****************** part6: 上报   *******************/
        /**********************************************************/
        @Override
        public void onReceiveElementCode(ElementCode elementCode) {
            Log.e(TAG, "onReceiveOIDFormat---> " + elementCode);
            //if (onDataReceiveListener != null) {
            //    onDataReceiveListener.onReceiveOIDSize( penOIDSize);
            //}
            long now = System.currentTimeMillis();
            if (now - time > 1000) {
                String intentAction;
                intentAction = ACTION_PEN_STATUS_CHANGE;
                broadcastUpdate(intentAction);
                Intent intent = new Intent(getBaseContext(), ElementActivity.class);
                //intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
                //intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
                intent.putExtra("value", elementCode.index);
                startActivity(intent);
                time = now;
            }
        }

        @Override
        public void onReceivePenHandwritingColor(int color) {
            Log.e(TAG, "receive hand write color is " + color);
        }


        /**********************************************************/
        /****************** part7: 其它   *******************/
        /**********************************************************/
        @Override
        public void onWriteCmdResult(final int code) {
            Log.i(TAG, "onWriteCmdResult: " + code);
            handlerThree.post(new Runnable() {
                @Override
                public void run() {
                    if (code != 0) {
                        Toast.makeText(getApplicationContext(), "WriteCmdResult :" + code, Toast.LENGTH_SHORT).show();
                    }
                }
            });
        }

        @Override
        public void onException(final BLEException exception) {
            handlerThree.post(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(getApplicationContext(), "onException :" + exception.getMessage(), Toast.LENGTH_SHORT).show();
                }
            });

        }

        //@Override
        public void onReceiveUsbStatus(int status) {

        }
    };
}

